/*-------------------------------------------------------------------------
 * auxprocess.c
 *	  与辅助进程相关的函数。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/backend/postmaster/auxprocess.c
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <unistd.h>
#include <signal.h>

#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/auxprocess.h"
#include "postmaster/bgwriter.h"
#include "postmaster/startup.h"
#include "postmaster/walwriter.h"
#include "replication/walreceiver.h"
#include "storage/bufmgr.h"
#include "storage/bufpage.h"
#include "storage/condition_variable.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/rel.h"


static void fc_ShutdownAuxiliaryProcess(int fc_code, Datum fc_arg);


/* ----------------
 *		全局变量
 * ----------------
 */

AuxProcType MyAuxProcType = NotAnAuxProcess;	/* 在 miscadmin.h 中声明 */


/*
 *	 AuxiliaryProcessMain
 *
 *	 辅助进程的主要入口点，例如 bgwriter、walwriter、walreceiver、bootstrapper 和共享内存检查器代码。
 *
 *	 此代码在这里仅仅是出于历史原因。
 */
void AuxiliaryProcessMain(AuxProcType fc_auxtype)
{
	Assert(IsUnderPostmaster);

	MyAuxProcType = fc_auxtype;

	switch (MyAuxProcType)
	{
		case StartupProcess:
			MyBackendType = B_STARTUP;
			break;
		case ArchiverProcess:
			MyBackendType = B_ARCHIVER;
			break;
		case BgWriterProcess:
			MyBackendType = B_BG_WRITER;
			break;
		case CheckpointerProcess:
			MyBackendType = B_CHECKPOINTER;
			break;
		case WalWriterProcess:
			MyBackendType = B_WAL_WRITER;
			break;
		case WalReceiverProcess:
			MyBackendType = B_WAL_RECEIVER;
			break;
		default:
			elog(ERROR, "something has gone wrong");
			MyBackendType = B_INVALID;
	}

	init_ps_display(NULL);

	SetProcessingMode(BootstrapProcessing);
	IgnoreSystemIndexes = true;

	/*
	 * 作为辅助进程，我们不会进行完整的 InitPostgres
	 * 锻炼，但即使在辅助进程中，有几件事也需要启动。
	 */

	/*
	 * 创建一个 PGPROC 以便我们可以使用 LWLocks。在 EXEC_BACKEND 的情况下，这个
	 * 已经由 SubPostmasterMain() 完成。
	 */
#ifndef EXEC_BACKEND
	InitAuxiliaryProcess();
#endif

	BaseInit();

	/*
	 * 为辅助进程分配 ProcSignalSlot。由于它没有
	 * BackendId，因此该槽基于辅助进程类型（MyAuxProcType）静态分配。
	 * 后端使用从 1 到 MaxBackends（含）的索引槽，
	 * 因此我们使用 MaxBackends + AuxProcType + 1 作为辅助进程的槽索引。
	 *
	 * 如果我们希望在特定的辅助进程类型上拥有多个实例，这将需要重新考虑。
	 */
	ProcSignalInit(MaxBackends + MyAuxProcType + 1);

	/*
	 * 辅助进程不运行事务，但它们可能仍然需要一个
	 * 资源所有者以管理在事务外获取的缓冲区固定（以及，或许，未来的其他事务）。
	 */
	CreateAuxProcessResourceOwner();


	/* 初始化后端状态信息 */
	pgstat_beinit();
	pgstat_bestart();

	/* 为 LWLock 清理注册一个关机前回调 */
	before_shmem_exit(fc_ShutdownAuxiliaryProcess, 0);

	SetProcessingMode(NormalProcessing);

	switch (MyAuxProcType)
	{
		case StartupProcess:
			StartupProcessMain();
			proc_exit(1);

		case ArchiverProcess:
			PgArchiverMain();
			proc_exit(1);

		case BgWriterProcess:
			BackgroundWriterMain();
			proc_exit(1);

		case CheckpointerProcess:
			CheckpointerMain();
			proc_exit(1);

		case WalWriterProcess:
			WalWriterMain();
			proc_exit(1);

		case WalReceiverProcess:
			WalReceiverMain();
			proc_exit(1);

		default:
			elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
			proc_exit(1);
	}
}

/*
 * 开始关闭辅助进程。这大致相当于 postinit.c 中的 ShutdownPostgres()。
 * 我们不能在辅助进程中运行事务，因此大部分 AbortTransaction() 的工作都不需要，
 * 但我们确实需要确保释放任何持有的 LWLocks。
 * （这在错误退出期间尤为重要。）
 */
static void fc_ShutdownAuxiliaryProcess(int fc_code, Datum fc_arg)
{
	LWLockReleaseAll();
	ConditionVariableCancelSleep();
	pgstat_report_wait_end();
}
